/*******************************************************************************
 * Copyright (c) 2002 IBM Corporation and others.
 * All rights reserved.   This program and the accompanying materials
 * are made available under the terms of the Common Public License v0.5
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v05.html
 * 
 * Contributors:
 * IBM - Initial implementation
 * Boris Pruessmann - reformatted sourcecode, changed cvs to perforce
 ******************************************************************************/
package net.sourceforge.perforce.core.syncinfo;

import net.sourceforge.perforce.core.internal.Policy;

/**
  * Provides a per-thread nested locking mechanism. A thread can acquire a
  * lock and then call acquire() multiple times. Other threads that try
  * and acquire the lock will be blocked until the first thread releases all
  * it's nested locks.
  * 
  * @version $Revision: 183 $
  * @author IBM
  * @author  <a href="mailto:bpruessmann@users.sourceforge.net">Boris Pruessmann</a>
  */
public class ReentrantLock 
{
	// --------------------------------------------------------------------------- Private Variables
	
	/** Stores the reference to the thread that currently owns the lock. */
	private Thread thread;
	/** Stores the nesting count. */
	private int nestingCount;
	
	// ------------------------------------------------------------------------- Public Constructors
	
	/** Constructor for ReentrantLock. */ 
	public ReentrantLock() 
	{
		this.thread = null;
		this.nestingCount = 0;
	}
	
	// ------------------------------------------------------------------------------ Public Methods

	/** Call this method to acquire the lock. */	
	public synchronized void acquire() 
	{
		// stop early if we've been interrupted -- don't enter the lock anew
		Thread thisThread = Thread.currentThread();

		// race for access to the lock -- does not guarantee fairness
		if (thread != thisThread) 
		{
			while (nestingCount != 0) 
			{
				try 
				{
					wait();
				} 
				catch (InterruptedException e) 
				{
					// keep waiting for the lock
				}
			}
			
			thread = thisThread;
		}
		nestingCount++;
	}
	
	/** Call this method to release the lock. */
	public synchronized void release() 
	{
		Thread thisThread = Thread.currentThread();
		Policy.assertTrue(thread == thisThread);
		
		if (--nestingCount == 0) 
		{
			thread = null;
			notifyAll();
		}
	}
	
	/** Call this method to retrieve the lock's nesting count.
	  *
	  * @return the Lock's nesting count. 
	  */
	public int getNestingCount() 
	{
		Thread thisThread = Thread.currentThread();
		Policy.assertTrue(thread == thisThread);

		return nestingCount;
	}
}
